package com.zqh.apiproductquery.service.impl;

import com.alibaba.fastjson.JSON;
import com.zqh.apiproductquery.redis.RedisUtil;
import com.zqh.apiproductquery.service.ApiProductQueryService;
import com.zqh.myfmmall.clients.ElasticSearchClient;
import com.zqh.myfmmall.clients.ProductQueryClient;
import com.zqh.myfmmall.constants.RedisExpireTime;
import com.zqh.myfmmall.result.Result;
import com.zqh.myfmmall.rowbeans.vo.ProductVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

;

/**
 * @Description :
 * @Author :kono淇杭哒、
 * @Create 2022-02-18 2:19
 */
@Service("apiProductQueryService")
public class ApiProductQueryServiceImpl implements ApiProductQueryService{
    @Autowired
    private ProductQueryClient productQueryClient;
    @Autowired
    private ElasticSearchClient elasticSearchClient;
    @Autowired
    private RedisUtil redisUtil;


    @Override
    public Result latestProducts(String categoryId) {
        //对应数据的基础key
        String redisKey = "latestProduct-categoryId:"+categoryId;
        List<ProductVo> latestProduct = (List<ProductVo>) redisUtil.get(redisKey);
        Result result = null;
        //categories-list一级缓存不为空
        if (latestProduct != null) {
            result = Result.success(latestProduct);
            //二级缓存配合redis分布式锁解决缓存击穿问题
        }else{
            List<ProductVo> latestProductBackUp = (List<ProductVo>) redisUtil.get(redisKey+"-backup");
            if (latestProductBackUp != null) {
                //使用缓存备份作为数据返回，在后面更新缓存数据的时间内的请求会有短时数据不同步问题
                result = Result.success(latestProductBackUp);
                //添加更新categories缓存的锁，从而只启动一个线程来更新缓存
                boolean isLocked = redisUtil.setnx(redisKey+"-lock", "1");
                //加锁成功则进入进行缓存更新操作
                try {
                    if (isLocked) {
                        Result productResult = productQueryClient.retrieveLatest(categoryId);
                        if (!productResult.getSuccess()){
                            return Result.internalServerError();
                        }
                        updateForRedisWithBackUp(redisKey,productResult.getData());
                    }
                } finally {
                    //释放锁
                    redisUtil.del("latestProduct-categoryId:"+categoryId+"-lock");
                }
                //初始categories-list和categories-list-backup缓存数据(即第一次访问时进行)，但是这里可以通过缓存预热来优化，暂时先这样写
            }else {
                result = productQueryClient.retrieveLatest(categoryId);
                if (!result.getSuccess()) {
                    return Result.internalServerError();
                }
                updateForRedisWithBackUp(redisKey,result.getData());
            }

        }
        return result;
    }

    @Override
    public Result highestSellingProduct(String categoryId) {
        //对应数据的基础key
        String redisKey = "highestSellingProduct-categoryId:"+categoryId;
        List<ProductVo> latestProduct = (List<ProductVo>) redisUtil.get(redisKey);
        Result result = null;
        //categories-list一级缓存不为空
        if (latestProduct != null) {
            result = Result.success(latestProduct);
            //二级缓存配合redis分布式锁解决缓存击穿问题
        }else{
            List<ProductVo> latestProductBackUp = (List<ProductVo>) redisUtil.get(redisKey+"-backup");
            if (latestProductBackUp != null) {
                //使用缓存备份作为数据返回，在后面更新缓存数据的时间内的请求会有短时数据不同步问题
                result = Result.success(latestProductBackUp);
                //添加更新categories缓存的锁，从而只启动一个线程来更新缓存
                boolean isLocked = redisUtil.setnx(redisKey+"-lock", "1");
                //加锁成功则进入进行缓存更新操作
                try {
                    if (isLocked) {
                        Result productResult = productQueryClient.retrieveHighestSellingVo(categoryId);
                        if (!productResult.getSuccess()){
                            return Result.internalServerError();
                        }
                        updateForRedisWithBackUp(redisKey,productResult.getData());
                    }
                } finally {
                    //释放锁
                    redisUtil.del(redisKey+"-lock");
                }
                //初始categories-list和categories-list-backup缓存数据(即第一次访问时进行)，但是这里可以通过缓存预热来优化，暂时先这样写
            }else {
                result = productQueryClient.retrieveHighestSellingVo(categoryId);
                if (!result.getSuccess()){
                    return Result.internalServerError();
                }
                updateForRedisWithBackUp(redisKey,result.getData());
            }

        }
        return result;
    }

    @Override
    public Result search(String key, Integer pageNum, Integer pageSize){
        return elasticSearchClient.searchProduct(key, pageNum, pageSize);
    }


    /**
     * 功能描述:
     * 设置某一数据的redis一级和二级缓存
     *
     * @param
     * @param key
     * @return void
     * @author kono曾淇杭哒！
     * @date 2022/3/16 20:54
     */
    public void updateForRedisWithBackUp(String key,Object value){
        //更新缓存
        redisUtil.set(key,value,
                RedisExpireTime.PRODUCT.getTime(),RedisExpireTime.PRODUCT.getTimeUnit());
        redisUtil.set(key+"-backup",value,
                RedisExpireTime.PRODUCT.getTime() + 30,RedisExpireTime.PRODUCT.getTimeUnit());
    }

}
